<?php
Class ResizeImage_Exception extends Exception {}

Class ResizeImage {
	protected $originalPath = null;
	protected $original = null;
	protected $thumb = null;
	protected $type = null;
	protected $outputType = null;
	protected $originalDimensions = array();
	protected $maxWidth = 150;
	protected $maxHeight = 100;
	protected $quality = 100;
	
	const MAX_WIDTH = 1;
	const MAX_HEIGHT = 2;
	const BEST_FIT = 3;
	const EXACT = 4;
	const NONE = 5;
	
	/**
	 * Constructor for the class, must be called
	 *
	 * @param string $imagePath The URL of the image file
	 */
	public function __construct($imagePath) {
		if(!file_exists($imagePath) || !is_readable($imagePath)) {
			throw new ResizeImage_Exception("The file '{$imagePath}' does not exist or is not readable");
		}
		$this->originalPath = $imagePath;
		$this->populateImageInfo();
	}
	
	protected function getThumbnailDimensions($type) {
		$w = $this->getWidth();
		$h = $this->getHeight();
		$nw = null;
		$nh = null;
		switch($type) {
			case ResizeImage::MAX_HEIGHT:
				$nh = ($h > $this->maxHeight) ? $this->maxHeight : $h;
				$nw = intval(($nh * $w) / $h);
				break;
			case ResizeImage::MAX_WIDTH:
				$nw = ($w > $this->maxWidth) ? $this->maxWidth : $w;
				$nh = intval(($nw * $h) / $w);
				break;
			case ResizeImage::BEST_FIT:
				if(($h / $this->maxHeight) >= ($w / $this->maxWidth)) {
					$nh = ($h > $this->maxHeight) ? $this->maxHeight : $h;
					$nw = intval(($nh * $w) / $h);
				} else {
					$nw = ($w > $this->maxWidth) ? $this->maxWidth : $w;
					$nh = intval(($nw * $h) / $w);
				}
				break;
			case ResizeImage::EXACT:
				$nw = $this->maxWidth;
				$nh = $this->maxHeight;
				break;
			case ResizeImage::NONE:
				$nw = $w;
				$nh = $h;
				break;
			default:
				throw new ResizeImage_Exception("Resize type is not valid.  It must be one of the following class constants: ResizeImage::MAX_HEIGHT, ResizeImage::MAX_WIDTH, ResizeImage::BEST_FIT, ResizeImage::EXACT");
		}
		return array('width' => $nw, 'height' => $nh);
	}
	
	protected function getWatermarkPos($type, $waterPosType) 
    {
    	$dimensions = $this->getThumbnailDimensions($type);
        switch($waterPosType)  { 
            case 'TL'://top and left
                $waterPosX = 0; 
                $waterPosY = 0; 
                break; 
            case 'TC'://top and center
                $waterPosX = ($dimensions['width'] - $this->waterWidth) / 2; 
                $waterPosY = 0; 
                break; 
            case 'TR'://top and right 
                $waterPosX = $dimensions['width'] - $this->waterWidth; 
                $waterPosY = 0; 
                break; 
            case 'CL'://center and left 
                $waterPosX = 0; 
                $waterPosY = ($dimensions['height'] - $this->waterHeight) / 2; 
                break; 
            case 'CC'://center and center 
                $waterPosX = ($dimensions['width'] - $this->waterWidth) / 2; 
                $waterPosY = ($dimensions['height'] - $this->waterHeight) / 2; 
                break; 
            case 'CR'://center and right 
                $waterPosX = $dimensions['width'] - $this->waterWidth; 
                $waterPosY = ($dimensions['height'] - $this->waterHeight) / 2; 
                break; 
            case 'BL'://bottom and left 
                $waterPosX = 0; 
                $waterPosY = $dimensions['height'] - $this->waterHeight * rand(115,125) / 100; 
                break; 
            case 'BC'://bottom and center
                $waterPosX = ($dimensions['width'] - $this->waterWidth) / 2; 
                $waterPosY = $dimensions['height'] - $this->waterHeight * rand(115,125) / 100; 
                break; 
            case 'BR'://bottom and right 
                $waterPosX = $dimensions['width'] - $this->waterWidth; 
                $waterPosY = $dimensions['height'] - $this->waterHeight * rand(115,120) / 100; 
                break;
            case 0: //random
            default:
                $waterPosX = rand(0,($dimensions['width'] - $this->waterWidth)); 
                $waterPosY = rand(0,($dimensions['height'] - $this->waterHeight));     
        }
        return array('x' => $waterPosX, 'y' => $waterPosY);
    } 	
	
	
	/**
	 * Sets the output type of thumbnail images.  If not called, the output type will be the same as input type.
	 *
	 * @param constant $type Valid values include the constants: IMAGETYPE_JPEG, IMAGETYPE_GIF, or IMAGETYPE_PNG
	 * @return ResizeImage The ResizeImage instance - used for 'fluent' access
	 */
	public function setOutputType($type) {
		if($type != IMAGETYPE_JPEG && $type != IMAGETYPE_GIF && $type != IMAGETYPE_PNG) {
			throw new ResizeImage_Exception("The output type must be one of the following constants IMAGETYPE_JPEG, IMAGETYPE_GIF, or IMAGETYPE_PNG");
		}
		$this->outputType = $type;
		return $this;
	}
	
	/**
	 * Returns the image type of the image used to instantiate the class
	 *
	 * @return constant One of the following constants: IMAGETYPE_JPEG, IMAGETYPE_GIF, or IMAGETYPE_PNG
	 */
	public function getImageType() {
		return $type;
	}
	
	/**
	 * Returns the width of the image used to instantiate the class
	 *
	 * @return int The width in pixels
	 */
	public function getWidth() {
		return $this->originalDimensions['width'];
	}
	
	/**
	 * Returns the height of the image used to instantiate the class
	 *
	 * @return int The height in pixels
	 */
	public function getHeight() {
		return $this->originalDimensions['height'];
	}
	
	/**
	 * Sets the maximum height to be used in thumbnail creation
	 *
	 * @param int $maxHeight The height in pixels.  Defaults to 100.
	 * @return ResizeImage The ResizeImage instance - used for 'fluent' access
	 */
	public function setMaxHeight($maxHeight) {
		$this->maxHeight = $maxHeight;
		return $this;
	}
	
	/**
	 * Sets the maximum width to be used in thumbnail creation
	 *
	 * @param int $maxWidth The width in pixels. Defaults to 150.
	 * @return ResizeImage The ResizeImage instance - used for 'fluent' access
	 */
	public function setMaxWidth($maxWidth) {
		$this->maxWidth = $maxWidth;
		return $this;
	}
	
	
	/**
	 * Sends the proper content-type header to the browser and renders the thumbnail.  ResizeImage::resize must be called prior to this method.
	 *
	 * @return ResizeImage The ResizeImage instance - used for 'fluent' access
	 */
	public function showThumbnail() {
		if(is_null($this->thumb)) {
			throw new ResizeImage_Exception("The image must be generated before you can show it");
		}
		header("Content-type: " . image_type_to_mime_type($this->outputType));
		$this->getThumb(NULL);
	}
	
	/**
	 * Saves the thumbnail to the filesystem.  ResizeImage::resize must be called prior to this method.
	 *
	 * @param string $filename The full file path (relative or absolute) where the image should be saved
	 * @return ResizeImage The ResizeImage instance - used for 'fluent' access
	 */
	public function saveThumbnail($filename) {
		$this->getThumb($filename);
	}
	
	public function saveWatermark($filename) {
		$this->getThumb($filename);
	}
	
	/**
	 * Sets the quality level for JPEG images
	 *
	 * @param int $quality An integer between 0 and 100, where 100 is the best quality.  Defaults to 100.
	 * @return ResizeImage The ResizeImage instance - used for 'fluent' access
	 */
	public function setJpegQuality($quality) {
		if(!is_int($quality) || $quality < 0 || $quality > 100) {
			throw new ResizeImage_Exception("Quality must be a positive integer less than or equal to 100");
		}
		$this->quality = $quality;
		return $this;
	}
	
	/**
	 * Resizes the image
	 *
	 * @param constant $type An image resize method.  Must be one of: ResizeImage::MAX_HEIGHT, ResizeImage::MAX_WIDTH, ResizeImage::BEST_FIT, ResizeImage::EXACT
	 * @return ResizeImage The ResizeImage instance - used for 'fluent' access
	 */
	public function resize($type = ResizeImage::MAX_HEIGHT) {
		$dimensions = $this->getThumbnailDimensions($type);
		$this->thumb = imagecreatetruecolor($dimensions['width'],$dimensions['height']);
		imagecopyresampled($this->thumb,$this->original,0,0,0,0,$dimensions['width'],$dimensions['height'],$this->getWidth(),$this->getHeight());
		return $this;
	}
	
	public function setWaterImageInfo($waterImagePath)
    {
        if(file_exists($waterImagePath) || is_readable($waterImagePath)) {
            $this->waterType       =   'image';
            $this->waterImage      =   &$waterImagePath;
            $waterImageInfo        =   getimagesize($this->waterImage);
            $this->waterWidth      =   $waterImageInfo[0];
            $this->waterHeight     =   $waterImageInfo[1];
            $this->waterImageType  =   $waterImageInfo[2];
            unset($waterImageInfo);
        } else {
            throw new ResizeImage_Exception("The file '{$waterImagePath}' does not exist or is not readable");
        }
    } 
    
    public function setWaterTextInfo($waterText = "test", $waterTextColor = "#000000", $waterTextSize = "5", $waterTextFont = "./couri.ttf")
    {
        $this->waterType     =  'text';
        if(strlen($waterTextColor) == 7) {
            $this->waterTextColor = &$waterTextColor;
        } else {
            throw new ResizeImage_Exception("The text color error");
        }
        $this->waterText       =   &$waterText;
        $this->waterTextSize   =   &$waterTextSize;
        $this->waterTextFont   =   &$waterTextFont;
        $waterTextInfo = imagettfbbox(ceil($this->waterTextSize*1.2), 0, $this->waterTextFont, $this->waterText); 
        $this->waterWidth    =  $waterTextInfo[4] - $waterTextInfo[6]; 
        $this->waterHeight   =  $waterTextInfo[1] - $waterTextInfo[7]; 
        unset($waterTextInfo);
    }
    
    protected function setWaterImageHandle()
    {
        switch($this->waterImageType) {
            case 1: $this->water = imagecreatefromgif($this->waterImage); break; 
            case 2: $this->water = imagecreatefromjpeg($this->waterImage); break; 
            case 3: $this->water = imagecreatefrompng($this->waterImage); break; 
            default: throw new ResizeImage_Exception("The watermark image type does not exist");
        }
    }
	
	public function watermark($type = ResizeImage::MAX_HEIGHT, $waterPosType = 0) 
	{
		$this->resize($type);
		imagealphablending($this->thumb, true); 

		$waterPos = $this->getWatermarkPos($type, $waterPosType);
        if($this->waterType == 'text') {
        	$color = imagecolorallocate($this->thumb, hexdec(substr($this->waterTextColor,1,2)), hexdec(substr($this->waterTextColor,3,2)), hexdec(substr($this->waterTextColor,5,2)));
            imagettftext($this->thumb, $this->waterTextSize, 0, $waterPos['x'], $this->waterHeight + $waterPos['y'], $color, $this->waterTextFont, $this->waterText);
        } else {
            $this->setWaterImageHandle();
            imagecopy($this->thumb, $this->water, $waterPos['x'], $waterPos['y'], 0, 0, $this->waterWidth,$this->waterHeight);
        }
        return $this;
	
	}
	
	protected function populateImageInfo() {
		$img_info = getimagesize($this->originalPath);
		switch($img_info[2]) {
			case IMAGETYPE_JPEG: 
				$type = IMAGETYPE_JPEG;
				$this->original = imagecreatefromjpeg($this->originalPath);
				break;
			case IMAGETYPE_GIF: 
				$type = IMAGETYPE_GIF;
				$this->original = imagecreatefromgif($this->originalPath);
				break;
			case IMAGETYPE_PNG: 
				$type = IMAGETYPE_PNG;
				$this->original = imagecreatefrompng($this->originalPath);
				break;
			default:
				throw new ResizeImage_Exception("Unkown file format - must be JPG, JPEG, GIF, or PNG");
		}
		$this->type = $type;
		$this->outputType = $type;
		$this->originalDimensions = array('width'=>$img_info[0],'height'=>$img_info[1]);
	}
	
	protected function getThumb($filename = NULL) {
		switch($this->outputType) {
			case IMAGETYPE_JPEG: 
				imagejpeg($this->thumb,$filename,$this->quality);
				break;
			case IMAGETYPE_GIF: 
				if(is_null($filename)) {
					imagegif($this->thumb);
				} else {
					imagegif($this->thumb,$filename);
				}
				break;
			case IMAGETYPE_PNG: 
				imagepng($this->thumb,$filename);
				break;
		}
	}
	
	public function __destruct() {
		if(is_resource($this->original)) imagedestroy($this->original);
		if(is_resource($this->thumb)) imagedestroy($this->thumb);
	}
}




